"""
Some unittest for the contest application.
"""

from django.test import TestCase
from django.db import IntegrityError

from cassebras.contest.models import Category, Slope, Competitor, \
                                     SuccessfullClimb

class TestContest(TestCase):
    """
    Class used to test the Category class
    """
    CATEGORY_NAME = 'A Category Name'
    
    def setUp(self):
        """
        Create default objects that will be used during 
        the other tests
        """
        cat = Category(name=TestContest.CATEGORY_NAME)
        cat.save()
        for i in range(1, 4):
            slope = Slope(number=i)
            slope.save()
            competitor = Competitor(name=str(i), category=cat, number=i)
            competitor.save()
    
    def test_rank_competitors(self):
        """
        Tests competitors ranking
        """
        slope = Slope.objects.all().get(id=1)
        cat = Category.objects.all().get(name=TestContest.CATEGORY_NAME)
        for i in range(1, 2):
            competitor = Competitor.objects.all().get(id=i)
            success = SuccessfullClimb(competitor=competitor, slope=slope)
            success.save()
        # We add one more Slope to Competitor with id=1 
        # => it will be ranked first
        competitor = Competitor.objects.get(id=1)
        # We take Slope with id 2 because it has not been added to 
        # competitor 1 yet
        slope2 = Slope.objects.all().get(id=2)
        success = SuccessfullClimb(competitor=competitor, slope=slope2)
        success.save()
        ranking = cat.rank_competitors()
        self.failUnlessEqual(ranking[0].number, competitor.number)

    def test_score(self):
        """
        Tests score evolution while adding/removing SuccessfullClimb
        """
        # Initially score of a Slope is equal to Slope.INITIAL_SCORE
        slope = Slope.objects.all().get(id=1)
        self.failUnlessEqual(slope.score, Slope.INITIAL_SCORE)
        
        # Initially score of a Competitor is null.
        comp = Competitor.objects.all().get(id=1)
        self.failUnlessEqual(comp.score, 0)
        
        # If only one Competitor successfully climbs the Slope, slope Score 
        # should be equal to Slope.INITIAL_SCORE
        success = SuccessfullClimb(competitor=comp, slope=slope)
        success.save()
        self.failUnlessEqual(Slope.objects.get(id=1).score, 
                             Slope.INITIAL_SCORE)
        self.failUnlessEqual(Competitor.objects.get(id=1).score, 
                             Slope.INITIAL_SCORE)
        
        # If we try to add the same Slope to the Competitor we should raise 
        # an error and Slope/Competitor scores should remain the sames
        comp = Competitor.objects.all().get(id=1)
        slope = Slope.objects.all().get(id=1)
        success = SuccessfullClimb(competitor=comp, slope=slope)
        self.assertRaises(IntegrityError, success.save)
        self.failUnlessEqual(Slope.objects.get(id=1).score, 
                             Slope.INITIAL_SCORE)
        
        # If another Competitor successfully climbs the Slope then the 
        # score of the Slope and of all Competitor that climb it should be 
        # updated
        comp2 = Competitor.objects.all().get(id=2)
        success = SuccessfullClimb(competitor=comp2, slope=slope)
        success.save()
        self.failUnlessEqual(Slope.objects.all().get(id=1).score, 
                             Slope.INITIAL_SCORE/2)
        self.failUnlessEqual(Competitor.objects.all().get(id=2).score, 
                             Slope.INITIAL_SCORE/2)
        self.failUnlessEqual(Competitor.objects.all().get(id=1).score, 
                             Slope.INITIAL_SCORE/2)
        
        # If an error id one and we need to remove a Slope to a Competitor then
        # Slope score should be updated, like the score of all the Competitor 
        # that climb it
        SuccessfullClimb.objects.all().get(competitor=comp2, 
                                           slope=slope).delete()
        self.failUnlessEqual(Slope.objects.all().get(id=1).score, 
                             Slope.INITIAL_SCORE)
        self.failUnlessEqual(Competitor.objects.all().get(id=2).score, 
                             0)
        self.failUnlessEqual(Competitor.objects.all().get(id=1).score, 
                             Slope.INITIAL_SCORE)
        